package com.cskaoyan.order.service.impl;

import com.cskaoyan.mall.commons.exception.BizException;
import com.cskaoyan.mall.commons.exception.ExceptionProcessorUtils;
import com.cskaoyan.mall.order.constant.OrderRetCode;
import com.cskaoyan.order.biz.TransOutboundInvoker;
import com.cskaoyan.order.biz.constant.OrderConstants;
import com.cskaoyan.order.biz.context.AbsTransHandlerContext;
import com.cskaoyan.order.biz.factory.OrderProcessPipelineFactory;
import com.cskaoyan.order.dal.entitys.Order;
import com.cskaoyan.order.dal.entitys.OrderItem;
import com.cskaoyan.order.dal.entitys.Stock;
import com.cskaoyan.order.dal.persistence.OrderItemMapper;
import com.cskaoyan.order.dal.persistence.OrderMapper;
import com.cskaoyan.order.dal.persistence.OrderShippingMapper;
import com.cskaoyan.order.dal.persistence.StockMapper;
import com.cskaoyan.order.dto.*;
import com.cskaoyan.order.service.OrderCoreService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
// @Transactional(rollbackFor = Exception.class)
public class OrderCoreServiceImpl implements OrderCoreService {


    @Autowired
    OrderMapper orderMapper;

    @Autowired
    OrderItemMapper orderItemMapper;

    @Autowired
    OrderShippingMapper orderShippingMapper;

    @Autowired
    OrderProcessPipelineFactory orderProcessPipelineFactory;

    @Autowired
    StockMapper stockMapper;


    /**
     * 创建订单的处理流程
     *
     * @param request
     * @return
     */
    @Override
    @Transactional
    public CreateOrderResponse createOrder(CreateOrderRequest request) {
        CreateOrderResponse response = new CreateOrderResponse();
        try {
            // 简单参数校验
            request.requestCheck();
            //创建pipeline对象
            TransOutboundInvoker invoker = orderProcessPipelineFactory.build(request);

            //启动pipeline
            invoker.start(); //启动流程（pipeline来处理）

            //获取处理结果
            AbsTransHandlerContext context = invoker.getContext();

            //把处理结果转换为response
            response = (CreateOrderResponse) context.getConvert().convertCtx2Respond(context);

        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.error("OrderCoreServiceImpl.createOrder Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }

    @Override
    @Transactional
    public CancelOrderResponse cancelOrder(CancelOrderRequest request) {
        CancelOrderResponse response = new CancelOrderResponse();
        try {
            //参数校验
            request.requestCheck();
            //查询订单
            Order order = orderMapper.selectByPrimaryKey(request.getOrderId());
            //获得当前订单的状态码
            Integer status = order.getStatus();
            // TODO: 2022/7/10 不清楚状态码的具体逻辑
            //不同的状态码，判断是否修改库存
            if (status == OrderConstants.ORDER_STATUS_INIT) {
                //修改库存
                updateStockAndOrderItemWhenCancel(request.getOrderId());
            }
            //更改状态码
            Order orderForUpdate = new Order();
            orderForUpdate.setOrderId(request.getOrderId());
            orderForUpdate.setStatus(OrderConstants.ORDER_STATUS_TRANSACTION_CANCEL);
            orderForUpdate.setUpdateTime(new Date());
            int rows = orderMapper.updateByPrimaryKeySelective(orderForUpdate);
            if (rows < 1) {
                throw new BizException(OrderRetCode.DB_EXCEPTION.getCode(), "取消订单更新状态码失败");
            }
            response.setCode(OrderRetCode.SUCCESS.getCode());
            response.setMsg(OrderRetCode.SUCCESS.getMessage());
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.error("OrderCoreServiceImpl.cancelOrder Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }

    @Override
    @Transactional
    public DeleteOrderResponse deleteOrder(DeleteOrderRequest request) {
        DeleteOrderResponse response = new DeleteOrderResponse();
        try {
            // 参数校验
            request.requestCheck();
            // todo 哪些状态的订单可以删除
            // 先查询订单
            Order order = orderMapper.selectByPrimaryKey(request.getOrderId());

            if (order.getStatus() == OrderConstants.ORDER_STATUS_INIT) {
                // 初始化的订单，既要删除数据也要修改库存
                // 需要先更新再删除
                updateStockWhenDelete(request);
                deleteOrderAndOrderItem(request);
            } else if (order.getStatus() == OrderConstants.ORDER_STATUS_TRANSACTION_CANCEL) {
                // 只需要删除数据
                deleteOrderAndOrderItem(request);
            } else {
                throw new BizException(OrderRetCode.DB_EXCEPTION.getCode(), "该订单不能删除");
            }
            response.setCode(OrderRetCode.SUCCESS.getCode());
            response.setMsg(OrderRetCode.SUCCESS.getMessage());
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.error("OrderCoreServiceImpl.deleteOrder Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }

    @Override
    public void updateStockAndOrderItemWhenCancel(String orderId) {
        List<OrderItem> orderItems = orderItemMapper.queryByOrderId(orderId);
        List<Long> ItemIdList = orderItems.stream().map(o -> o.getItemId()).collect(Collectors.toList());
        Example example = new Example(OrderItem.class);
        example.createCriteria()
                //.andIn("itemId", ItemIdList)
                .andEqualTo("orderId", orderId);
        OrderItem orderItemForUpdateStatus = new OrderItem();
        orderItemForUpdateStatus.setStatus(OrderConstants.ITEM_ORDER_STATUS_RELEASE);
        orderItemMapper.updateByExampleSelective(orderItemForUpdateStatus, example);
        // if (i < 1) {
        //     throw new BizException(OrderRetCode.DB_EXCEPTION.getCode(), "取消订单更新OrderItem失败");
        // }
        // 添加行锁
        List<Stock> stocksForUpdate = stockMapper.findStocksForUpdate(ItemIdList);
        for (OrderItem orderItem : orderItems) {
            Long itemId = orderItem.getItemId();
            Integer num = orderItem.getNum();

            Stock stock = new Stock();
            stock.setItemId(itemId);
            stock.setLockCount(-num);
            stock.setStockCount(Long.valueOf(num));
            stockMapper.updateStock(stock);
        }
    }

    private void updateStockWhenDelete(DeleteOrderRequest request) {
        List<OrderItem> orderItems = orderItemMapper.queryByOrderId(request.getOrderId());
        List<Long> ItemIdList = orderItems.stream().map(o -> o.getItemId()).collect(Collectors.toList());
        // 添加行锁
        List<Stock> stocksForUpdate = stockMapper.findStocksForUpdate(ItemIdList);
        for (OrderItem orderItem : orderItems) {
            Long itemId = orderItem.getItemId();
            Integer num = orderItem.getNum();

            Stock stock = new Stock();
            stock.setItemId(itemId);
            stock.setLockCount(-num);
            stock.setStockCount(Long.valueOf(num));
            stockMapper.updateStock(stock);
        }
    }

    private void deleteOrderAndOrderItem(DeleteOrderRequest request) {
        // 删除订单表的数据
        int delete = orderMapper.deleteByPrimaryKey(request.getOrderId());
        // 通过订单id删除订单商品关联表
        Example example = new Example(OrderItem.class);
        example.createCriteria()
                .andEqualTo("orderId", request.getOrderId());
        int deleteByExample = orderItemMapper.deleteByExample(example);
        // 通过订单id删除物流表
        int deleteByPrimaryKey = orderShippingMapper.deleteByPrimaryKey(request.getOrderId());
    }

}
